using Sirenix.OdinInspector;
using UnityEngine;
using UnityEngine.UI;

namespace Custom.Daily.Toolkit
{
    /// <summary>
    /// 引导小图标
    /// </summary>
    public class ObjectiveMarker : MonoBehaviour
    {
        [LabelText("3D场景目标位置")] public Transform targetTransform;
        [LabelText("屏幕标点Icon")] public Image img;
        [LabelText("模式选择"),Tooltip("第三人称射击为 Over watch 模式")] public Mode updateMode;

        [BoxGroup("Icon 距离屏幕四周的最小间距"), LabelText("上边界")] public int offsetUp;
        [BoxGroup("Icon 距离屏幕四周的最小间距"), LabelText("下边界")] public int offsetDown;
        [BoxGroup("Icon 距离屏幕四周的最小间距"), LabelText("左边界")] public int offsetLeft;
        [BoxGroup("Icon 距离屏幕四周的最小间距"), LabelText("右边界")] public int offsetRight;

        public enum Mode
        {
            [LabelText("简单模式")]
            Common,
            [LabelText("高精度模式")]
            Overwatch,
        }

        private void LateUpdate()
        {
            switch (updateMode)
            {
                case Mode.Common:
                    Method1();
                    break;
                case Mode.Overwatch:
                    Method2();
                    break;
                default:
                    break;
            }
        }

        private void Method1()
        {
            var main = Camera.main;
            var camTransform = main.transform;
            var newPos = new Vector3();
            var delta = targetTransform.position - camTransform.position;
            var dot = Vector3.Dot(camTransform.forward, delta);

            if (dot < 0)
            {
                var projectedPos = camTransform.position + (delta - camTransform.forward * (Vector3.Dot(camTransform.forward, delta) * 1.01f));
                newPos = main.WorldToScreenPoint(projectedPos);
            }
            else
            {
                newPos = main.WorldToScreenPoint(targetTransform.position);
            }

            if (newPos.x > Screen.width - offsetRight || newPos.x < offsetLeft || newPos.y > Screen.height - offsetUp ||
                newPos.y < offsetDown)
                newPos = KClamp(newPos);

            img.transform.position = newPos;
        }

        private void Method2()
        {
            var main = Camera.main;
            var camTransform = main.transform;

            var vFov = main.fieldOfView;
            var radHFov = 2 * Mathf.Atan(Mathf.Tan(vFov * Mathf.Deg2Rad / 2) * main.aspect);
            var hFov = Mathf.Rad2Deg * radHFov;

            var deltaUnitVec = (targetTransform.position - camTransform.position).normalized;

            var vdegobj = Vector3.Angle(Vector3.up, deltaUnitVec) - 90f;
            var vdegcam = Vector3.SignedAngle(Vector3.up, camTransform.forward, camTransform.right) - 90f;

            var vdeg = vdegobj - vdegcam;

            var hdeg = Vector3.SignedAngle(Vector3.ProjectOnPlane(camTransform.forward, Vector3.up),
                Vector3.ProjectOnPlane(deltaUnitVec, Vector3.up), Vector3.up);

            vdeg = Mathf.Clamp(vdeg, -89f, 89f);
            hdeg = Mathf.Clamp(hdeg, hFov * -0.5f, hFov * 0.5f);

            var projectedPos = Quaternion.AngleAxis(vdeg, camTransform.right) *
                               Quaternion.AngleAxis(hdeg, camTransform.up) * camTransform.forward;
            Debug.DrawLine(camTransform.position, camTransform.position + projectedPos, Color.red);

            var newPos = main.WorldToScreenPoint(camTransform.position + projectedPos);

            if (newPos.x > Screen.width - offsetRight || newPos.x < offsetLeft || newPos.y > Screen.height - offsetUp ||
                newPos.y < offsetDown)
                newPos = KClamp(newPos);

            img.transform.position = newPos;
        }

        private Vector3 KClamp(Vector3 newPos)
        {
            Vector2 center = new(Screen.width / 2, Screen.height / 2);
            var k = (newPos.y - center.y) / (newPos.x - center.x);

            if (newPos.y - center.y > 0)
            {
                newPos.y = Screen.height - offsetUp;
                newPos.x = center.x + (newPos.y - center.y) / k;
            }
            else
            {
                newPos.y = offsetDown;
                newPos.x = center.x + (newPos.y - center.y) / k;
            }

            if (newPos.x > Screen.width - offsetRight)
            {
                newPos.x = Screen.width - offsetRight;
                newPos.y = center.y + (newPos.x - center.x) * k;
            }
            else if (newPos.x < offsetLeft)
            {
                newPos.x = offsetLeft;
                newPos.y = center.y + (newPos.x - center.x) * k;
            }

            return newPos;
        }
    }
}